package com.alex.wechat.component.gateway;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alex.wechat.mp.config.WxConsts;
import com.alex.wechat.mp.util.WxCryptUtilEx;

import me.chanjar.weixin.component.api.WxCompConfigStorage;
import me.chanjar.weixin.message.bean.WxXmlMessage;
import me.chanjar.weixin.message.rule.WxMessageRouter;

/**
 * 用户发送给公众号的消息（由公众号第三方平台代收）。此时， 消息XML体中， ToUserName（即接收者）为公众号的原始ID（可通过
 * 《接口说明》中的获取授权方信息接口来获得）
 * 
 * @author Debenson
 * @since 0.1
 */
@Controller
@RequestMapping("/wxCompCoreController")
public class WxComponentCoreController {
  private static final Logger logger = LoggerFactory.getLogger(WxComponentCoreController.class);

  @Autowired
  private WxCompConfigStorage compConfig;
  @Autowired
  private WxMessageRouter wxRouter;

  /**
   * 负责处理开放平台发过来的公众号与小程序消息与事件
   * 
   * @param appId
   *          小程序或公众号的appid
   * @param request
   * @param response
   * @return
   * @throws Exception
   */
  @RequestMapping(value = "/{appId}/wechat", produces = "application/xml; charset=UTF-8")
  public void wechat(@PathVariable String appId, HttpServletRequest request,
      HttpServletResponse response) throws Exception {
    response.setContentType("text/html;charset=utf-8");
    response.setStatus(HttpServletResponse.SC_OK);

    if (!WxCryptUtilEx.checkSignature(compConfig.getToken(), request)) {
      // 消息签名不正确，说明不是公众平台发过来的消息
      response.getWriter().println("非法请求");
      return;
    }

    final String echoStr = request.getParameter(WxConsts.PARAM_ECHO_STR);
    if (StringUtils.isNotBlank(echoStr)) {
      // 说明是一个仅仅用来验证的请求，回显echostr
      String echoStrOut = String.copyValueOf(echoStr.toCharArray());
      response.getWriter().println(echoStrOut);
    }

    String encryptType = request.getParameter(WxConsts.PARAM_ENCRYPT_TYPE);
    if (StringUtils.isBlank(encryptType)) {
      encryptType = WxConsts.ENCRYPT_TYPE_RAW;
    }
    if (WxConsts.ENCRYPT_TYPE_RAW.equalsIgnoreCase(encryptType)) {
      // 使用明码传输
      processRawEncrypt(request, response);

    } else if (WxConsts.ENCRYPT_TYPE_AES.equalsIgnoreCase(encryptType)) {
      // 是aes加密的消息
      processAesEncrypt(request, response);

    } else {
      response.getWriter().println("不可识别的加密类型");
    }
  }

  /**
   * @param request
   * @param response
   * @throws Exception
   */
  private void processRawEncrypt(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    throw new RuntimeException("暂不支持明文传输");
    // // 明文传输的消息
    // response.setContentType("application/xml; charset=UTF-8");
    // WxXmlMessage inMessage = WxXmlMessage.fromXml(request.getInputStream());
    //
    // final String outMessage = this.wxRouter.route(inMessage);
    // if (outMessage != null) {
    // if (logger.isInfoEnabled()) {
    // logger.info("回复内容为: {}", outMessage);
    // }
    // response.getWriter().write(outMessage);
    // }
  }

  /**
   * @param request
   * @param response
   * @throws Exception
   */
  private void processAesEncrypt(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    String msgSignature = request.getParameter(WxConsts.PARAM_MSG_SIGNATURE);
    String nonce = request.getParameter(WxConsts.PARAM_NONCE);
    String timestamp = request.getParameter(WxConsts.PARAM_TIMESTAMP);
    response.setContentType("application/xml; charset=UTF-8");

    WxXmlMessage inMessage = WxCryptUtilEx.fromEncryptedXml(request.getInputStream(), compConfig,
        timestamp, nonce, msgSignature);
    if (logger.isInfoEnabled()) {
      logger.info("第三方平台消息解密后内容为：\n{} ", inMessage.toString());
    }

    final String outMessage = wxRouter.routeComponent(inMessage);
    // if (StringUtils.isNotBlank(WxAppContext.getAppId())) {
    // outMessage = wxRouter.routeApp(inMessage);
    // } else if (StringUtils.isNotBlank(WxContext.getAppId())) {
    // outMessage = wxRouter.routeMp(inMessage);
    // }

    if (outMessage != null) {
      if (logger.isInfoEnabled()) {
        logger.info("回复第三方平台内容为(加密前): {}", outMessage);
      }
      response.getWriter().write(WxCryptUtilEx.toEncryptedXml(outMessage, compConfig));
    } else {
      if (logger.isInfoEnabled()) {
        logger.info("没有回复内容");
      }
    }
  }

}
